"""
四川麻将游戏引擎工具函数
"""
import numpy as np
from typing import List, Dict, Tuple
from sichuanmajiang.engine.cards import Tile, Suit, SuitTile, TileSet, create_standard_mahjong_set


def tile_to_index(tile: Tile) -> int:
    """
    将麻将牌转换为索引
    总共27种不同的牌：筒、条、万各9种
    """
    if tile.suit == Suit.BAMBOO:
        return tile.value - 1  # 0-8
    elif tile.suit == Suit.CHARACTER:
        return 9 + tile.value - 1  # 9-17
    elif tile.suit == Suit.DOT:
        return 18 + tile.value - 1  # 18-26
    return -1


def index_to_tile(index: int) -> Tile:
    """
    将索引转换为麻将牌
    """
    if 0 <= index <= 8:
        return SuitTile(Suit.BAMBOO, index + 1)
    elif 9 <= index <= 17:
        return SuitTile(Suit.CHARACTER, index - 9 + 1)
    elif 18 <= index <= 26:
        return SuitTile(Suit.DOT, index - 18 + 1)
    raise ValueError(f"Invalid tile index: {index}")


def hand_to_vector(tiles: List[Tile]) -> np.ndarray:
    """
    将手牌转换为向量表示
    向量长度为27，每个元素表示对应牌的数量（0-4）
    """
    vector = np.zeros(27, dtype=np.int32)
    for tile in tiles:
        idx = tile_to_index(tile)
        if idx >= 0:
            vector[idx] += 1
    return vector


def vector_to_hand(vector: np.ndarray) -> List[Tile]:
    """
    将向量转换回手牌
    """
    tiles = []
    for idx in range(27):
        count = int(vector[idx])
        tile = index_to_tile(idx)
        tiles.extend([tile] * count)
    return tiles


def game_state_to_features(game_state: Dict, player_index: int) -> np.ndarray:
    """
    将游戏状态转换为特征向量
    这将用于深度学习模型的输入
    """
    # 基本特征：手牌表示（27维）
    player = game_state["players"][player_index]
    hand_vector = hand_to_vector(player["hand"])
    
    # 副露牌表示（27维，每个元素表示该牌是否在副露中）
    exposed_vector = np.zeros(27, dtype=np.int32)
    for group in player["exposed_tiles"]:
        for tile in group:
            idx = tile_to_index(tile)
            exposed_vector[idx] = 1
    
    # 弃牌堆表示（27维，每个元素表示该牌被打出的次数）
    discard_vector = np.zeros(27, dtype=np.int32)
    for tile in game_state.get("discard_pile", []):
        idx = tile_to_index(tile)
        discard_vector[idx] += 1
    
    # 上一张打出的牌（27维独热编码）
    last_discard_vector = np.zeros(27, dtype=np.int32)
    if game_state.get("last_discarded_tile"):
        idx = tile_to_index(game_state["last_discarded_tile"])
        last_discard_vector[idx] = 1
    
    # 对手手牌数量信息（3维）
    opponent_hand_counts = []
    for i, p in enumerate(game_state["players"]):
        if i != player_index:
            opponent_hand_counts.append(len(p["hand"]))
    opponent_hand_counts = np.array(opponent_hand_counts, dtype=np.int32)
    
    # 剩余牌墙数量
    wall_count = np.array([game_state["wall_count"]], dtype=np.int32)
    
    # 回合信息
    round_number = np.array([game_state.get("round_number", 0)], dtype=np.int32)
    
    # 组合所有特征
    features = np.concatenate([
        hand_vector,
        exposed_vector,
        discard_vector,
        last_discard_vector,
        opponent_hand_counts,
        wall_count,
        round_number
    ])
    
    return features


def calculate_tile_efficiency(tiles: List[Tile]) -> Dict[Tile, float]:
    """
    计算每张牌的效率值
    效率值基于该牌能组成的有效组合数量
    """
    efficiency = {}
    tile_counts = {}
    
    # 统计每种牌的数量
    for tile in tiles:
        if tile not in tile_counts:
            tile_counts[tile] = 0
        tile_counts[tile] += 1
    
    # 对于每种牌，计算其效率
    for tile, count in tile_counts.items():
        # 基本效率计算
        eff = 0.0
        
        # 刻子效率
        if count >= 2:
            eff += 1.0
        
        # 顺子效率（所有牌都是序数牌）
        # 计算与该牌相邻的牌的需求
        value = tile.value
        suit = tile.suit
        
        # 检查可能的顺子组合
        for offset in [-2, -1, 0]:
            if 1 <= value + offset <= 7:
                # 检查是否可以组成顺子
                needed_tiles = [
                    SuitTile(suit, value + offset),
                    SuitTile(suit, value + offset + 1),
                    SuitTile(suit, value + offset + 2)
                ]
                
                # 计算缺少的牌数
                missing = 0
                for needed in needed_tiles:
                    if needed not in tile_counts or tile_counts[needed] == 0:
                        missing += 1
                
                # 根据缺少的牌数调整效率
                if missing == 0:
                    eff += 2.0  # 已完成的顺子
                elif missing == 1:
                    eff += 1.0  # 听牌的顺子
                elif missing == 2:
                    eff += 0.5  # 潜在的顺子
        
        # 对子效率
        if count >= 1:
            eff += 0.5
        
        efficiency[tile] = eff
    
    return efficiency


def recommend_tile_to_discard(tiles: List[Tile]) -> Tile:
    """
    推荐应该打出的牌
    基于效率值选择效率最低的牌
    """
    efficiency = calculate_tile_efficiency(tiles)
    
    # 找到效率最低的牌
    min_efficiency = float('inf')
    min_tile = None
    
    for tile, eff in efficiency.items():
        if eff < min_efficiency:
            min_efficiency = eff
            min_tile = tile
    
    return min_tile


def generate_all_possible_hands() -> List[List[Tile]]:
    """
    生成所有可能的手牌组合（用于测试）
    注意：实际上不可能生成所有组合，这里只是一个示例
    """
    # 简化版：生成一些示例手牌
    sample_hands = []
    
    # 示例1：一对将牌 + 四组刻子
    hand1 = []
    # 一对将牌（一万）
    hand1.extend([SuitTile(Suit.DOT, 1)] * 2)
    # 四组刻子
    hand1.extend([SuitTile(Suit.BAMBOO, 1)] * 3)
    hand1.extend([SuitTile(Suit.CHARACTER, 2)] * 3)
    hand1.extend([SuitTile(Suit.DOT, 3)] * 3)
    hand1.extend([SuitTile(Suit.BAMBOO, 5)] * 3)
    sample_hands.append(hand1)
    
    # 示例2：一对将牌 + 四组顺子
    hand2 = []
    # 一对将牌（二条）
    hand2.extend([SuitTile(Suit.CHARACTER, 2)] * 2)
    # 四组顺子
    for i in range(1, 4):
        hand2.extend([SuitTile(Suit.BAMBOO, i), SuitTile(Suit.BAMBOO, i+1), SuitTile(Suit.BAMBOO, i+2)])
    for i in range(4, 7):
        hand2.extend([SuitTile(Suit.DOT, i), SuitTile(Suit.DOT, i+1), SuitTile(Suit.DOT, i+2)])
    # 移除一张牌，使总数为14
    hand2.pop()
    sample_hands.append(hand2)
    
    return sample_hands


def simulate_random_game(num_players: int = 4, max_rounds: int = 100) -> Dict:
    """
    模拟一场随机游戏
    返回游戏结果统计
    """
    from sichuanmajiang.engine.game import MahjongGame, AIPlayer
    
    # 创建玩家
    players = [AIPlayer(f"玩家{i+1}") for i in range(num_players)]
    
    # 创建游戏实例
    game = MahjongGame(players)
    game.initialize_game()
    
    # 运行游戏
    round_count = 0
    while not game.is_game_over and round_count < max_rounds:
        current_player = game.players[game.current_player_index]
        
        # 摸牌
        game.player_draw(game.current_player_index)
        
        # 决定打牌
        if current_player.hand.tiles:
            # 简单AI：随机打出一张牌
            tile_to_discard = current_player.hand.tiles[0]
            game.process_player_action(game.current_player_index, "discard", tile=tile_to_discard)
        
        round_count += 1
    
    # 返回统计结果
    return {
        "winner": game.winner.name if game.winner else None,
        "final_scores": {p.name: p.score for p in game.players},
        "rounds_played": round_count,
        "tiles_discarded": len(game.discard_pile)
    }


def analyze_hand_strength(tiles: List[Tile]) -> Dict[str, float]:
    """
    分析手牌强度
    返回一个包含各种强度指标的字典
    """
    from sichuanmajiang.engine.rules import check_hu
    
    # 基础强度分析
    is_hu = check_hu(tiles)
    
    # 计算进张数（听牌时能胡的牌数）
    tile_counts = hand_to_vector(tiles)
    winning_tiles = []
    
    if not is_hu:
        # 尝试每种牌，看是否能胡
        for idx in range(34):
            if tile_counts[idx] < 4:  # 不能超过4张
                temp_vector = tile_counts.copy()
                temp_vector[idx] += 1
                temp_hand = vector_to_hand(temp_vector)
                if check_hu(temp_hand):
                    winning_tiles.append(index_to_tile(idx))
    
    # 计算搭子数量
    搭子数量 = 0
    # 这里可以实现更复杂的搭子识别算法
    
    # 计算孤立牌数量
    孤立牌数量 = 0
    # 这里可以实现孤立牌识别算法
    
    # 综合评分
    score = 0.0
    if is_hu:
        score = 100.0
    else:
        # 基于进张数评分
        score = min(90.0, len(winning_tiles) * 10.0)
        # 可以添加更多评分因子
    
    return {
        "is_hu": is_hu,
        "winning_tiles": winning_tiles,
        "winning_tiles_count": len(winning_tiles),
        "搭子数量": 搭子数量,
        "孤立牌数量": 孤立牌数量,
        "overall_strength": score
    }